package com.poi.demo.parser;

import lombok.Getter;
import lombok.Setter;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.xddf.usermodel.chart.*;
import org.apache.poi.xwpf.usermodel.XWPFChart;
import org.apache.poi.xwpf.usermodel.XWPFDocument;

import java.io.InputStream;
import java.util.*;

/**
 * <p>Word图表解析器</p>
 *
 * @author Allen Yang
 * @datetime 2021/11/18 14:53
 */
@Setter
@Getter
public class WordChartParser extends WordContentParser {

    private List<ChartReplace> chartReplaces;

    public WordChartParser(InputStream in, List<ChartReplace> chartReplaces) {
        super(in);
        this.chartReplaces = chartReplaces;
    }

    public WordChartParser(XWPFDocument doc, List<ChartReplace> chartReplaces) {
        super(doc);
        this.chartReplaces = chartReplaces;
    }

    public WordChartParser(InputStream in) {
        super(in);
    }

    public WordChartParser(XWPFDocument doc) {
        super(doc);
    }

    public WordChartParser(String path) {
        super(path);
    }

    @Setter
    @Getter
    public static class ChartReplace {
        //图表标题
        private String chartTitle;
        //x分类轴标题
        private String categoryAxisTitle;
        //y值轴标题
        private String valueAxesTitle;
        //图表在word文档中的xml名称，格式 /word/charts/chart1.xml | /word/charts/chart2.xml
//        private String chartXmlName;
        //图表在模板中的下标，从1开始
        private int index;
        //图表分类名称
        private String[] categoryNames;
        //图表数据行值
        private List<LineValue> lineValues;
    }

    @Setter
    @Getter
    public static class LineValue {
        //图表数据名称
        private String lineName;
        //图表数据行值
        private Number[] lineValue;
        //设置标记样式
        private MarkerStyle markerStyle;

        public LineValue() {
            // 设置标记样式
            markerStyle = MarkerStyle.NONE;
        }

    }

    @Override
    public XWPFDocument replace() {
        if (Objects.isNull(getDoc())) {
            throw new RuntimeException(ERR_MSG_DOC_NOT_LOADED);
        }
        if (CollectionUtils.isEmpty(chartReplaces)) {
            throw new RuntimeException(ERR_MSG_PARAM_NOT_INITIALIZED);
        }

        List<XWPFChart> charts = getDoc().getCharts();
        if (CollectionUtils.isEmpty(charts)) {
            throw new RuntimeException(ERR_MSG_TEMPLATE_CHART_NOT_EXIST.replace("${name}", ""));
        }

        Map<Integer, XWPFChart> templateChartMap = new HashMap<>();
        for (int i = 1, size = charts.size(); i <= size; i++) {
            String key = charts.get(i - 1).toString().replaceAll("Name: ", "")
                    .replaceAll(" - Content Type: application/vnd\\.openxmlformats-officedocument\\.drawingml\\.chart\\+xml", "").trim();
            key = key.replace("/word/charts/chart", "").replace(".xml", "");
            templateChartMap.put(Integer.valueOf(key), charts.get(i - 1));
        }

        chartReplaces.forEach(lineChartReplace -> {
            if (CollectionUtils.isEmpty(lineChartReplace.getLineValues())) {
                throw new RuntimeException(ERR_MSG_PARAM_NOT_INITIALIZED);
            }
            //校验元素个数是否一致
            int dataLength = lineChartReplace.getCategoryNames().length;
            for (int i = 0, size = lineChartReplace.getLineValues().size(); i < size; i++) {
                if (lineChartReplace.getLineValues().get(i).getLineValue().length != dataLength) {
                    throw new RuntimeException(ERR_MSG_ROW_ELEMENT_MISMATCH.replace("${index}", String.valueOf(i)));
                }
            }
            //校验图表是否存在
            XWPFChart templateChart = templateChartMap.get(lineChartReplace.getIndex());
            if (Objects.isNull(templateChart)) {
                throw new RuntimeException(ERR_MSG_TEMPLATE_CHART_NOT_EXIST.replace("${index}", String.valueOf(lineChartReplace.getIndex())));
            }
        });

        //逐个图表进行内容替换
        chartReplaces.forEach(lineChartReplace -> {
            XWPFChart templateChart = templateChartMap.get(lineChartReplace.getIndex());
            templateChart.setTitleText(lineChartReplace.getChartTitle());//图表标题
            XDDFCategoryDataSource categoryDataSource = XDDFDataSourcesFactory.fromArray(lineChartReplace.getCategoryNames());//分类名称
            templateChart.getChartSeries().forEach(chartData -> {
                if (Objects.nonNull(chartData.getCategoryAxis())) {
                    chartData.getCategoryAxis().setTitle(lineChartReplace.getCategoryAxisTitle());//x轴标题
                }
                if (Objects.nonNull(chartData.getValueAxes())) {
                    chartData.getValueAxes().forEach(axis -> {
                        axis.setTitle(lineChartReplace.getValueAxesTitle());//y轴标题
                    });
                }
                //删除模板自带的图表数据
                for (int i = 0, count = chartData.getSeriesCount(); i < count; i++) {
                    chartData.removeSeries(0);
                }

                //渲染数据
                lineChartReplace.getLineValues().forEach(lineValue -> {
                    XDDFNumericalDataSource<Number> values = XDDFDataSourcesFactory.fromArray(lineValue.getLineValue());
                    // 图表加载数据
                    XDDFChartData.Series series = chartData.addSeries(categoryDataSource, values);
                    // 图表例标题
                    series.setTitle(lineValue.getLineName(), null);
                    // 设置标记样式
                    setMarkerStyle(series, lineValue);
                });

                // 绘制
                templateChart.plot(chartData);

            });
        });

        return getDoc();
    }

    private void setMarkerStyle(XDDFChartData.Series series, LineValue lineValue) {
        if (series instanceof XDDFLineChartData.Series) {
            ((XDDFLineChartData.Series)series).setMarkerStyle(lineValue.getMarkerStyle());
        }
        //其它图表
    }

}
